
#include <cstdlib>

#include <QApplication>
#include <QComboBox>
#include <QGroupBox>
#include <QFormLayout>
#include <QPushButton>
#include <QHBoxLayout>
#include <QSlider>
#include <QVBoxLayout>
#include <QWidget>

#include "boids/flockwidget.h"

int main(int iArgc, char* astrArgv[])
{
    QApplication kApp(iArgc, astrArgv);

    // Window widgets.
    QWidget kWindow;
    QWidget* pkPanel = new QWidget(&kWindow);
    FlockWidget* pkWidget = new FlockWidget(&kWindow);

    QGroupBox* pkControlsBox = new QGroupBox("Controls", pkPanel);
    QGroupBox* pkTogglesBox = new QGroupBox("Toggles", pkPanel);
    QGroupBox* pkFlockingBox = new QGroupBox("Flocking", pkPanel);

    QSlider* pkUpdateDelaySlider = new QSlider(Qt::Horizontal, pkPanel);
    pkUpdateDelaySlider->setRange(0, 100);

    QPushButton* pkResetAgentsButton = new QPushButton("Reset", pkPanel);

    QSlider* pkAgentCountSlider = new QSlider(Qt::Horizontal, pkPanel);
    pkAgentCountSlider->setRange(0, 100);

    QPushButton* pkShowBodiesToggle = new QPushButton("Bodies", pkPanel);
    pkShowBodiesToggle->setCheckable(true);

    QPushButton* pkShowRangesToggle = new QPushButton("Ranges", pkPanel);
    pkShowRangesToggle->setCheckable(true);

    QPushButton* pkShowQuadtreeToggle = new QPushButton("Quadtree", pkPanel);
    pkShowQuadtreeToggle->setCheckable(true);

    QComboBox* pkRepulsionFunctionComboBox = new QComboBox(pkPanel);
    pkRepulsionFunctionComboBox->addItem("Constant");
    pkRepulsionFunctionComboBox->addItem("Linear");
    pkRepulsionFunctionComboBox->addItem("Quadratic");
    pkRepulsionFunctionComboBox->addItem("Exponential");
    QSlider* pkRepulsionFactorSlider = new QSlider(Qt::Horizontal, pkPanel);
    pkRepulsionFactorSlider->setRange(0, 100);

    QComboBox* pkAlignementFunctionComboBox = new QComboBox(pkPanel);
    pkAlignementFunctionComboBox->addItem("Constant");
    pkAlignementFunctionComboBox->addItem("Linear");
    pkAlignementFunctionComboBox->addItem("Quadratic");
    pkAlignementFunctionComboBox->addItem("Exponential");
    QSlider* pkAlignementFactorSlider = new QSlider(Qt::Horizontal, pkPanel);
    pkAlignementFactorSlider->setRange(0, 100);

    QComboBox* pkAttractionFunctionComboBox = new QComboBox(pkPanel);
    pkAttractionFunctionComboBox->addItem("Constant");
    pkAttractionFunctionComboBox->addItem("Linear");
    pkAttractionFunctionComboBox->addItem("Quadratic");
    pkAttractionFunctionComboBox->addItem("Exponential");
    QSlider* pkAttractionFactorSlider = new QSlider(Qt::Horizontal, pkPanel);
    pkAttractionFactorSlider->setRange(0, 100);

    QComboBox* pkDisturbanceComboBox = new QComboBox(pkPanel);
    pkDisturbanceComboBox->addItem("None");
    pkDisturbanceComboBox->addItem("Attractive");
    pkDisturbanceComboBox->addItem("Repulsive");

    QComboBox* pkDisturbanceFunctionComboBox = new QComboBox(pkPanel);
    pkDisturbanceFunctionComboBox->addItem("Constant");
    pkDisturbanceFunctionComboBox->addItem("Linear");
    pkDisturbanceFunctionComboBox->addItem("Quadratic");
    pkDisturbanceFunctionComboBox->addItem("Exponential");

    QSlider* pkDisturbanceFactorSlider = new QSlider(Qt::Horizontal, pkPanel);
    pkDisturbanceFactorSlider->setRange(0, 1000);

    // Hierarchy.
    QHBoxLayout* pkWindowLayout = new QHBoxLayout();
    QVBoxLayout* pkPanelLayout = new QVBoxLayout();
    QFormLayout* pkControlsLayout = new QFormLayout();
    QVBoxLayout* pkTogglesLayout = new QVBoxLayout();
    QFormLayout* pkFlockingLayout = new QFormLayout();

    kWindow.setLayout(pkWindowLayout);

    pkWindowLayout->addLayout(pkPanelLayout);
    pkWindowLayout->addWidget(pkWidget);

    pkPanelLayout->addWidget(pkControlsBox);
    pkPanelLayout->addWidget(pkTogglesBox);
    pkPanelLayout->addWidget(pkFlockingBox);
    pkPanelLayout->addStretch(1);

    pkControlsBox->setLayout(pkControlsLayout);
    pkTogglesBox->setLayout(pkTogglesLayout);
    pkFlockingBox->setLayout(pkFlockingLayout);

    pkControlsLayout->addRow("Update delay", pkUpdateDelaySlider);
    pkControlsLayout->addWidget(pkResetAgentsButton);
    pkControlsLayout->addRow("Agent count", pkAgentCountSlider);

    pkTogglesLayout->addWidget(pkShowBodiesToggle);
    pkTogglesLayout->addWidget(pkShowRangesToggle);
    pkTogglesLayout->addWidget(pkShowQuadtreeToggle);

    pkFlockingLayout->addRow("Repulsion", pkRepulsionFunctionComboBox);
    pkFlockingLayout->addRow("", pkRepulsionFactorSlider);
    pkFlockingLayout->addRow("Alignement", pkAlignementFunctionComboBox);
    pkFlockingLayout->addRow("", pkAlignementFactorSlider);
    pkFlockingLayout->addRow("Attraction", pkAttractionFunctionComboBox);
    pkFlockingLayout->addRow("", pkAttractionFactorSlider);
    pkFlockingLayout->addRow("Disturbance", pkDisturbanceComboBox);
    pkFlockingLayout->addRow("", pkDisturbanceFunctionComboBox);
    pkFlockingLayout->addRow("", pkDisturbanceFactorSlider);

    // Make connections.
    QObject::connect(pkUpdateDelaySlider, SIGNAL(valueChanged(int)),
                     pkWidget, SLOT(setUpdateDelay(int)));
    QObject::connect(pkResetAgentsButton, SIGNAL(clicked()),
                     pkWidget, SLOT(reset()));
    QObject::connect(pkAgentCountSlider, SIGNAL(valueChanged(int)),
                     pkWidget, SLOT(setAgentCount(int)));
    QObject::connect(pkShowBodiesToggle, SIGNAL(toggled(bool)),
                     pkWidget, SLOT(setBodiesVisible(bool)));
    QObject::connect(pkShowRangesToggle, SIGNAL(toggled(bool)),
                     pkWidget, SLOT(setRangesVisible(bool)));
    QObject::connect(pkShowQuadtreeToggle, SIGNAL(toggled(bool)),
                     pkWidget, SLOT(setQuadtreeVisible(bool)));
    QObject::connect(pkRepulsionFunctionComboBox, SIGNAL(currentIndexChanged(int)),
                     pkWidget, SLOT(setRepulsionFunction(int)));
    QObject::connect(pkRepulsionFactorSlider, SIGNAL(valueChanged(int)),
                     pkWidget, SLOT(setRepulsionFactor(int)));
    QObject::connect(pkAlignementFunctionComboBox, SIGNAL(currentIndexChanged(int)),
                     pkWidget, SLOT(setAlignementFunction(int)));
    QObject::connect(pkAlignementFactorSlider, SIGNAL(valueChanged(int)),
                     pkWidget, SLOT(setAlignementFactor(int)));
    QObject::connect(pkAttractionFunctionComboBox, SIGNAL(currentIndexChanged(int)),
                     pkWidget, SLOT(setAttractionFunction(int)));
    QObject::connect(pkAttractionFactorSlider, SIGNAL(valueChanged(int)),
                     pkWidget, SLOT(setAttractionFactor(int)));
    QObject::connect(pkDisturbanceComboBox, SIGNAL(currentIndexChanged(int)),
                     pkWidget, SLOT(setDisturbance(int)));
    QObject::connect(pkDisturbanceFunctionComboBox, SIGNAL(currentIndexChanged(int)),
                     pkWidget, SLOT(setDisturbanceFunction(int)));
    QObject::connect(pkDisturbanceFactorSlider, SIGNAL(valueChanged(int)),
                     pkWidget, SLOT(setDisturbanceFactor(int)));

    // Setup initial state.
    pkUpdateDelaySlider->setValue(33);
    pkAgentCountSlider->setValue(10);
    pkShowBodiesToggle->setChecked(true);
    pkShowRangesToggle->setChecked(false);
    pkShowQuadtreeToggle->setChecked(false);
    pkRepulsionFactorSlider->setValue(50);
    pkAlignementFactorSlider->setValue(50);
    pkAttractionFactorSlider->setValue(50);

    // Show.
    kWindow.show();

    return kApp.exec();
}
